package org.amse.korovkin.ciphering.model.cipher.monocipher;
import java.io.*;
import java.util.HashSet;
import java.util.Random;
import org.amse.korovkin.ciphering.Main;
import org.amse.korovkin.ciphering.model.cipher.IKey;

public class ChangeTable implements IKey{
    private int[] myLetter1 = new int[Main.NUM_LETTERS];
    private int[] myLetter2 = new int[Main.NUM_LETTERS];
    private int myNum = 0;    

    public static char toLowerCase(char ch) {
        if (ch >= 'A' && ch <= 'Z') {
            return ((char)(((int) ch) + 32));            
        } else return ch;
    }
    public static char toUpperCase(char ch) {
        if (ch >= 'a' && ch <= 'z') {
            return ((char)(((int) ch) - 32));
        } else return ch;
    }
    public void add(char letter1, char letter2){
        if (myNum <Main.NUM_LETTERS) {
            myLetter1[myNum] = (int)letter1;
            myLetter2[myNum] = (int)letter2;
            myNum++;
        } else {
            throw new ArrayIndexOutOfBoundsException("ChangeTable is full. ");
        }
    }    

    public void removeLast() {
        if (myNum > 0) {
            myNum--;
            myLetter1[myNum] = 0;
            myLetter2[myNum] = 0;
        } else {
            throw new ArrayIndexOutOfBoundsException();
        }
    }
    public int getLetter2(char ch) {
        for (int i = 0; i < myNum; i++) {
            if (myLetter1[i] == (int) ch) {
                return myLetter2[i];
            }
        }
        return -1;
    }
    public int getLetter1(char ch) {
        for (int i = 0; i < myNum; i++) {
            if (myLetter2[i] == (int) ch) {
                return myLetter1[i];
            }
        }
        return -1;
    }
    public void setLetter2(char letter1, char letter2) {
        for (int i = 0; i < myNum; i++) {
            if (myLetter1[i] == (int) letter1) {
                myLetter2[i] = letter2;
                return;
            }
        }
    }
    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < myNum; i++) {
            res.append((char)myLetter1[i] + " " + (char)myLetter2[i] + "\n");
        }
        return res.toString();
    }
    public void writeToFile(String inputFile)
            throws IOException {
        FileWriter fWriter = new FileWriter(inputFile);
        for (int i = 0; i < myNum; i++) {
                 fWriter.write((char)myLetter1[i]);
                 fWriter.write((char)myLetter2[i]);
                 fWriter.write("\n");
         }
        fWriter.close();
    }
    public void readFromFile(String inFile)
            throws IOException, ArrayIndexOutOfBoundsException {
        char ch1 = ' ';
        char ch2 = ' ';
        int counter = 0;
        FileReader fr = new FileReader(inFile);
        int i = 0;
        while ((i = fr.read()) != -1) {
            if ((char) i != '\r' && (char) i != '\n') {
                counter++;
                if (counter % 2 == 1) {
                    ch1 = (char) i;
                } else {
                    ch2 = (char) i;
                    this.add(ch1, ch2);
                }
            }
        }
        fr.close();
    }

    @Override
    public ChangeTable clone() {
        ChangeTable table = new ChangeTable();
        for (int i = 0; i < myNum; i++) {
            table.add((char) myLetter1[i], (char) myLetter2[i]);
        }
        return table;
    }
    public boolean equals(ChangeTable table) {
        boolean res = false;
        if (table.myNum != myNum) {
            return res;
        } else {
            for (int i = 0; i < myNum; i++) {
                if (myLetter2[i] != table.getLetter2((char)myLetter1[i])) {
                    return res;
                }
            }
            return true;
        }
    }
    
    @SuppressWarnings({"unchecked"})
    public static void generate() {
        HashSet alphabet = new HashSet();
        for (int i = 0; i < 26; i++) {
            alphabet.add(i + (int) 'a');
        }
        alphabet.add((int) ' ');
        ChangeTable table = new ChangeTable();
        for (int i = 0; i < 26; i++) {
            int index = i + (int) 'a';
            Random random = new Random();
            table.add((char) index, (char) (random.nextInt(255) % 26 + (int) 'a'));
        }
        for (int i = 0; i < 26; i++) {
            if (alphabet.contains(table.myLetter2[i])) {
                alphabet.remove(table.myLetter2[i]);
            } else {
                table.myLetter2[i] = (Integer) (alphabet.iterator().next());
                alphabet.remove(table.myLetter2[i]);
            }
        }
        table.add(' ', (char) (int) ((Integer) (alphabet.iterator().next())));
        try {
            table.writeToFile(IKey.KEY_PATH);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    private void setLetter2(char ch, int index) {
        myLetter2[index] = (int) ch;
    }
    private int getLetter2(int index) {
        return myLetter2[index];
    }

}
